package com.ruoyi.generator.util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class jisuanTool {
    /**
     * 计算在当前年度中，当前时间与给定的开始时间和结束时间之间已经过去的月份。
      * 
     * 该方法主要用于判断合同或项目的有效期内，在当前年度内已经过去的月份数。
     * 如果当前时间不在给定的时间段内，则返回 0。
     * 
     * @param startDate 开始时间（Date 类型）
     * @param endDate   结束时间（Date 类型）
     * @return 在当前年度中已经过去的月份。如果当前时间不在给定的时间段内，则返回 0。
     */
    public static int calculateElapsedMonthsThisYear(Date startDate, Date endDate) {
        Date currentDate = new Date(); // 获取当前时间

        // 检查当前时间是否在开始时间和结束时间之间
        if (currentDate.after(startDate) && currentDate.before(endDate)) {
            Calendar startCal = Calendar.getInstance();
            startCal.setTime(startDate);

            Calendar currentCal = Calendar.getInstance();
            currentCal.setTime(currentDate);

            // 判断开始时间是否在10号之前
            boolean isBefore10th = startCal.get(Calendar.DAY_OF_MONTH) < 10;

            // 只考虑当前年度的月份
            int startMonth = startCal.get(Calendar.MONTH);
            int currentMonth = currentCal.get(Calendar.MONTH);

            // 如果开始月份在当前年份，则计算之间的月份
            if (startCal.get(Calendar.YEAR) == currentCal.get(Calendar.YEAR)) {
                // 如果开始时间在10号之前，当月算作一个月
                if (isBefore10th) {
                    return currentMonth - startMonth + 1; // 包括当前月份
                } else {
                    // 如果开始时间在10号之后，从下个月开始计数
                    return currentMonth - startMonth; // 不包括当前月份
                }
            } else {
                // 如果开始时间不在当前年份，仅返回当前月份数
                return currentMonth + 1; // 包括从1月至当前月份
            }
        }
        // 合同已经过期或结束
        return 0;
    }


    /**
     * 计算两个日期之间的月份差，并可选生成从起始日期的下个月开始的月份字符串数组。
     * 
     * 该方法支持两种返回模式：
     * 1. 如果 generateMonthList 为 false，则返回两个日期之间的总月份数。
     * 2. 如果 generateMonthList 为 true，则返回从起始日期的下个月开始到结束日期的所有月份字符串数组。
     * 
     * 特殊逻辑：如果起始日期的日部分大于等于10号，则当月不计入第一个完整月份。
     * 
     * @param startDate       合同的起始日期
     * @param endDate         结束日期
     * @param generateMonthList 是否生成月份字符串数组
     * @return 如果 generateMonthList 为 true，返回月份字符串数组；否则返回累计的月份数
     */
    public static Object calculateMonthsBetweenDates(Date startDate, Date endDate, boolean generateMonthList) {
        // 将 java.util.Date 转换为 LocalDate
        LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        // 判断开始时间是否在15号之前
        boolean isBefore10th = startLocalDate.getDayOfMonth() <= 15;

        // 计算月份差
        long yearDifference = endLocalDate.getYear() - startLocalDate.getYear();
        long monthDifference = endLocalDate.getMonthValue() - startLocalDate.getMonthValue();
        long totalMonthDifference = yearDifference * 12 + monthDifference;

        // 如果开始时间在10号之后，当月不算作一个月，从下个月开始计数
        if (!isBefore10th) {
            totalMonthDifference--; // 减去当月
        }

        // 新增逻辑：如果时间间隔不足一个月，抛出异常
        if (totalMonthDifference < 1) {
            throw new IllegalArgumentException("合同时间有误，时间间隔不足一个月");
        }

        if (!generateMonthList) {
            return (int) totalMonthDifference;
        } else {
            // 生成月份字符串数组
            List<String> monthList = new ArrayList<>();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");

            // 从下个月开始生成
            LocalDate currentMonth = startLocalDate.plusMonths(isBefore10th ? 0 : 1); // 如果在10号之后，从下个月开始
            for (int i = 0; i < totalMonthDifference; i++) {
                monthList.add(currentMonth.format(formatter));
                currentMonth = currentMonth.plusMonths(1);
            }

            return monthList;
        }
    }


    /**
     * 获取指定日期到当前日期的月份差值。
     * 
     * 该方法计算指定日期与当前日期之间的月份数差值，结果以整数形式返回。
     * 
     * @param dateTimeStr 指定日期
     * @return 月份差值（以整数表示）
     */
    public static int getMonth(Date dateTimeStr) {
        // 将 Date 转换为 ZonedDateTime
        ZonedDateTime zonedDateTime = dateTimeStr.toInstant().atZone(ZoneId.systemDefault());

        // 转换为 LocalDate
        LocalDate date = zonedDateTime.toLocalDate();

        // 获取当前日期
        LocalDate currentDate = LocalDate.now();

        // 计算两个日期之间的差值（以月为单位）
        long monthsDifference = ChronoUnit.MONTHS.between(date, currentDate);

        return (int) monthsDifference;
    }

    /**
     * 计算合同的总运维周期（以月为单位）。
     * 
     * 该方法通过比较合同的起始日期和结束日期，计算出合同的总运维周期，单位为月。
     * 
     * @param startDate 合同开始日期
     * @param endDate   合同结束日期
     * @return 合同的总运维周期（月数）
     */
    public static int calculateContractPeriod(Date startDate, Date endDate) {
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);

        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);

        int years = endCal.get(Calendar.YEAR) - startCal.get(Calendar.YEAR);
        int months = endCal.get(Calendar.MONTH) - startCal.get(Calendar.MONTH);
        return years * 12 + months;
    }

    /**
     * 计算开工运维周期（从开始时间到当前时间的月份差）。
     * 
     * 该方法用于计算从合同起始日期到当前日期的运维周期，单位为月。
     * 特殊逻辑：如果起始日期的日部分大于等于10号，则当月不计入第一个完整月份。
     * 
     * @param startDate 合同的起始日期
     * @return 开工运维周期（月份数）
     */
    public static int calculateOperationPeriod(Date startDate) {
        // 获取当前时间
        Calendar currentCal = Calendar.getInstance();
        currentCal.setTime(new Date()); // 当前时间

        // 设置开始时间
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);

        // 判断开始时间是否在10号之前
        boolean isBefore10th = startCal.get(Calendar.DAY_OF_MONTH) < 10;

        // 计算年份差和月份差
        int years = currentCal.get(Calendar.YEAR) - startCal.get(Calendar.YEAR);
        int months = currentCal.get(Calendar.MONTH) - startCal.get(Calendar.MONTH);

        // 总月份差
        int totalMonths = years * 12 + months;

        // 如果开始时间在10号之后，当月不算作一个月，从下个月开始计数
        if (!isBefore10th) {
            totalMonths--; // 减去当月
        }
        // 10号前场景+1（与calculateElapsedMonthsThisYear保持一致）
        else {
            totalMonths += 1;
        }

        // 如果当前时间早于开始时间，返回0
        if (totalMonths < 0) {
            return 0;
        }

        return totalMonths;
    }

//    public static void main(String[] args) throws ParseException {
//        Date Startdata = new Date();
//        System.out.println(Startdata);
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        Date endDate = sdf.parse("2026-06-06");
//        System.out.println("开始时间"+Startdata);
//        System.out.println("结束时间"+endDate);
//        int kaigong =calculateOperationPeriod(Startdata);
//        int bennian=calculateElapsedMonthsThisYear(Startdata,  endDate);
//        System.out.println("kaigong:"+kaigong);
//        System.out.println("bennian:"+bennian);
//
//    }

    /**
     * 计算本年约定回款金额。
     * 
     * 该方法根据合同的有效金额、支付类型以及合同起始日期，计算出本年度内应支付的回款金额。
     * 支持多种支付类型（如月结、季度、半年、全年等），并处理跨年情况。
     * 
     * @param effectiveAmount 合同有效金额
     * @param paymentType 支付类型（1-月结合同，2-季度合同等）
     * @param startDate 合同开始日期
     * @return 本年约定回款金额的BigDecimal对象
     */
    public static BigDecimal calculateYearAgreedPayment(double effectiveAmount, String paymentType, Date startDate) {
        // 获取当前年份
        int currentYear = Calendar.getInstance().get(Calendar.YEAR);
        // 将开始日期转换为LocalDate
        LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 当前年份的最后一天
        LocalDate endOfYearDate = LocalDate.of(currentYear, 12, 31);

        // 处理跨年情况
        if (startLocalDate.getYear() > currentYear) {
            return BigDecimal.ZERO; // 合同开始在下一年，本年无回款
        }
        if (startLocalDate.getYear() < currentYear) {
            startLocalDate = LocalDate.of(currentYear, 1, 1); // 从本年1月1日开始计算
        }

        // 计算开始日期到年底的总月数
        long totalMonths = ChronoUnit.MONTHS.between(startLocalDate, endOfYearDate);
        int denominator = 0; // 分母（用于计算每期金额）
        int monthsPerPeriod = 0; // 每期包含的月份数

        // 根据支付类型选择分母和周期
        switch (paymentType) {
            case "1": // 月结合同
                // 检查金额是否能被12整除
                if (effectiveAmount % 12 != 0) {
                    if (effectiveAmount % 4 == 0) { // 优先尝试4个季度（3个月）
                        denominator = 4;
                        monthsPerPeriod = 3;
                    } else if (effectiveAmount % 6 == 0) { // 次选6个半年（6个月）
                        denominator = 6;
                        monthsPerPeriod = 6;
                    } else { // 默认按12个月分摊
                        denominator = 12;
                        monthsPerPeriod = 1;
                    }
                } else { // 能被12整除时直接按月计算
                    denominator = 12;
                    monthsPerPeriod = 1;
                }
                break;
            case "2": // 季度合同
                denominator = 4; // 4个季度
                monthsPerPeriod = 3;
                break;
            case "3": // 半年合同
                denominator = 2; // 2个半年
                monthsPerPeriod = 6;
                break;
            case "4": // 年合同
                denominator = 1; // 全年一次性
                monthsPerPeriod = 12;
                break;
            case "5": // 验收后结算
                return BigDecimal.ZERO; // 该类型不产生本年回款
            default:
                denominator = 12; // 默认按月处理
                monthsPerPeriod = 1;
        }

        // 计算每期金额（保留两位小数）
        BigDecimal perPeriodAmount = new BigDecimal(effectiveAmount).divide(new BigDecimal(denominator), 2, RoundingMode.HALF_UP);
        // 计算本年剩余的完整周期数
        long periods = totalMonths / monthsPerPeriod;
        // 返回总金额
        return perPeriodAmount.multiply(new BigDecimal(periods));
    }
}
